<?php

namespace tmcore\services\upload;

use tmcore\base\BaseManage;
use tmcore\exceptions\UploadException;
use tmcore\services\ConfigService;
use think\exception\ValidateException;
use think\file\UploadedFile;

abstract class BaseUpload extends BaseManage
{
    /**
     * 文件
     * @var null
     */
    protected $file = null;

    /**
     * 文件信息
     * @var array
     */
    protected array $fileInfo = [];

    /**
     * 保存路径
     * @var string
     */
    protected string $savePath = '';

    /**
     * 文件名称
     * @var string
     */
    protected string $filename = '';

    /**
     * 文件配置
     * @var array
     */
    protected array $fileConfig = [];

    /**
     * 是否返回全路径
     * @var bool
     */
    protected bool $isFullPath = false;

    /**
     * 初始化
     * @param array $config 配置参数
     */
    protected function initialize(array $config)
    {
        if($config) {
            $this->fileConfig = $config;
        } else {
            $this->fileConfig = (new ConfigService())->getConfig($this->name,'upload');
        }
    }

    /**
     * 获取文件配置
     * @return array
     */
    public function getFileConfig()
    {
        return $this->fileConfig;
    }

    /**
     * 设置保存文件信息
     * @param string $path 保存文件路径
     * @param string $name 保存文件名称
     * @param bool $is_full_path 是否返回全路径
     * @return $this
     */
    public function setSaveInfo(string $path, string $name = '', bool $is_full_path = false)
    {
        $this->savePath = $path;
        if($name)$this->filename = $name;
        if($is_full_path)$this->isFullPath = $is_full_path;
        return $this;
    }

    /**
     * 获取存储路径
     * @param string $type
     * @return string
     * @throws UploadException
     */
    protected function getSavePath($type = 'image')
    {
        return $this->savePath ? : 'uploads/'. ($type . 's') . '/' . date('Ymd');
    }

    /**
     * 获取文件后缀
     * @param string $url
     * @return string
     */
    protected function getFileExt($url)
    {
        $ext = strtolower(substr(strrchr($url,"."),1));
        return strlen($ext) < 10?$ext:'jpg';
    }

    /**
     * 设置保存文件信息
     * @param string $name 保存文件名称
     * @param bool $multifile 是否多文件
     * @return array|UploadedFile
     * @throws UploadException
     */
    protected function getFileInfo(string $name, $multifile = false)
    {
        if(!$multifile) {
            $this->file = request()->file($name) ?? null;
            if (empty($this->file)) {
                throw new UploadException('未找到上传文件的信息');
            }

            $this->fileInfo = [
                'file'         => $this->file,
                'ext'          => $this->file->extension(),
                'size'         => $this->file->getSize(),
                'md5'          => $this->file->hash('md5'),
                'upload_type'  => $this->fileConfig['upload_driver'] ?? 'local',
                'originalName' => $this->file->getOriginalName(),
                'fileName'     => $this->buildSaveName('', $this->filename)
            ];
        } else {
            $files = request()->file($name) ?? null;
            if (!is_array($files)) {
                $this->file = [$files];
            } else {
                $this->file = $files;
            }
            if (empty($this->file)) {
                throw new UploadException('未找到上传文件的信息');
            }
            foreach($files as $key => $file) {
                $this->fileInfo[$key] = [
                    'file'         => $file,
                    'ext'          => $file->extension(),
                    'size'         => $file->getSize(),
                    'md5'          => $file->hash('md5'),
                    'upload_type'  => $this->fileConfig['upload_driver'] ?? 'local',
                    'originalName' => $file->getOriginalName(),
                    'fileName'     => $this->buildSaveName($file->extension())
                ];
            }
        }

        return $this->file;
    }

    /**
     * 验证器验证
     * @param string $name
     * @param array $rule
     * @param null $file
     * @throws UploadException
     */
    protected function validate($name, $rule, $file = null) {
        try {
            validate([$name => $this->extractValidate($rule)])->check([$name => $file?:$this->file]);
        } catch (ValidateException $e) {
            throw new UploadException($this->languageChange($e->getMessage()));
        }
    }

    /**
     * 生成保存文件名
     *
     * @param string $ext
     * @param string $file_name
     * @return string
     */
    public function buildSaveName($ext = '', $file_name = ''): string
    {
        // 扩展名
        $ext = strtolower($ext?: $this->file->extension());

        if($file_name) {
            return $file_name == 'TM_FILE_ORIGINAL_NAME'?$this->file->getOriginalName():$file_name . ".{$ext}";
        } else {
            // 自动生成文件名
            return substr(md5(microtime()), 5, 10)
                . str_pad(rand(0, 9999), 5, '0', STR_PAD_LEFT)
                . ".{$ext}";
        }
    }

    /**
     * 英文转为中文
     * @param $msg
     * @return string
     */
    protected function languageChange($msg)
    {
        $data = [
            // 上传错误信息
            'unknown upload error'                       => '未知上传错误！',
            'file write error'                           => '文件写入失败！',
            'upload temp dir not found'                  => '找不到临时文件夹！',
            'no file to uploaded'                        => '没有文件被上传！',
            'only the portion of file is uploaded'       => '文件只有部分被上传！',
            'upload File size exceeds the maximum value' => '上传文件大小超过了最大值！',
            'upload write error'                         => '文件上传保存错误！',
        ];

        return $data[$msg] ?? $msg;
    }

    /**
     * 提取上传验证
     * @param array $rule
     * @return string
     */
    protected function extractValidate(array $rule)
    {
        $validate = [];
        foreach ($rule as $key => $value) {
            $validate[] = $key . ':' . (is_array($value) ? implode(',', $value) : $value);
        }
        return implode('|', $validate);
    }

    /**
     * 上传文件
     * @param string $name 文件对象 name
     * @param array $rule 上传规则 ['fileSize' => 0, 'fileExt' => 'jpg', 'image' => '200,200,jpg']
     * @param string $file_type 文件类型 image-图片 file-文件 video-视频 audio-音频
     * @return bool|array 文件信息
     */
    abstract public function upload(string $name, array $rule, string $file_type);

    /**
     * 批量上传文件
     * @param string $name 文件对象 name
     * @param array $rule 上传规则 ['fileSize' => 0, 'fileExt' => 'txt']
     * @param string $file_type 文件类型 image-图片 file-文件 video-视频 audio-音频
     * @return bool|array 文件信息数组
     */
    abstract public function batchUpload(string $name, array $rule, string $file_type);

    /**
     * 远程文件下载存储
     * @param string $url 文件路径
     * @param string $file_type 文件类型 image-图片 file-文件 video-视频 audio-音频
     * @return bool|array
     */
    abstract public function fetch(string $url, string $file_type = 'image');

    /**
     * 删除文件
     * @param string $path 文件路径
     * @return bool
     */
    abstract public function delete(string $path);
}